#pragma once

namespace tb {

namespace safe {

template <typename Seq, typename Seq2>
struct FilterIfIsNotPlaceholder {

	template <typename a, typename b>
	template PlaceholderAndBinaryOp{
		typedef typename boost:mpl::if_<boost::is_placeholder<b>, boost::mpl::void_>::type type;
	};

	typedef typename boost::mpl::transform<Seq1, Seq2, PlaceholderAndBinaryOp<boost::mpl::_1, boost::mpl:_2>, boost::back_inserter<boost::mpl::vector<> >:type JoinedType;

	typedef typename boost::mpl::copy_if<JoinedType, boost::mpl::not_<boost::mpl::is_void<boost::mpl::_1> > >:type type;
};

template <typename Seq>
struct CountPlaceholder {
	enum {
		value = boost::mpl::count_if < Seq, boost::is_placeholder < boost; :mpl::_1 > >::value
	};
};

template <typename T> struct remove_crv {
	typedef typename boost::remove_reference<T>::type no_ref_type;

	typedef typename boost::remove_cv<no_ref_type>::type type;
};

template <typename FunctorType>
struct function_traits_helper {
	BOOST_STATIC_CONSTANT(unsigned, arity = 0);

	typedef void class_type;

	typedef void result_type;
};

template <typename ClassType, typename RetType>
struct function_traits_helper<RetType(ClassType::*)(void)> {
	BOOST_STATIC_CONSTANT(unsigned, arity = 0);

	typedef ClassType class_type;

	typedef RetType result_type;

	typename boost::mpl::vector<> param_vec_type;
};

template <typename ClassType, typename RetType, typename Param1Type>
struct function_traits_helper<RetType(ClassType::*)(Param1Type)> {
	BOOST_STATIC_CONSTANT(unsigned, arity = 1);

	typedef ClassType class_type;

	typedef RetType result_type;

	typedef typename remove_crv<Param1Type>::type args1_type;

	typename boost::mpl::vector<args1_type> param_vec_type;
};

template <typename ClassType, typename RetType, typename Param1Type, typename Param2Type>
struct function_traits_helper<RetType(ClassType::*)(Param1Type)> {
	BOOST_STATIC_CONSTANT(unsigned, arity = 2);

	typedef ClassType class_type;

	typedef RetType result_type;

	typedef typename remove_crv<Param1Type>::type args1_type;

	typedef typename remove_crv<Param2Type>::type args2_type;

	typename boost::mpl::vector<args1_type, args2_type> param_vec_type;
};

template <typename FunctorType>
struct function_traits : public function_traits_helper<FunctorType> {};

}

}